using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace LS.GameKit.Editor
{
    [CustomPropertyDrawer(typeof(GameEnum), true)]
    public class GameEnumInspector: PropertyDrawer
    {
        private GUIContent m_CurrentValueContent = new GUIContent();
        private GUIContent m_EmptyContent = new GUIContent("<Empty>");
        private readonly List<string> m_EnumTypeNames = new List<string>();
        private readonly Dictionary<string,string[]> m_EnumGUIArrays = new Dictionary<string, string[]>();

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            GameEnum gameEnum = (GameEnum)property.boxedValue;
            if (string.IsNullOrEmpty(gameEnum.EnumTypeName()) || string.IsNullOrEmpty(gameEnum.EnumName()))
                m_CurrentValueContent.text = m_EmptyContent.text;
            else
                m_CurrentValueContent.text = gameEnum.ToString();
            
            float labelWidth = EditorGUIUtility.labelWidth;
            Rect labelPosition = new Rect(position.x, position.y, labelWidth, position.height);
            Rect controlPosition = new Rect(position.x + labelWidth + 2.5f, position.y, position.width - labelWidth - 2.5f, position.height);
            EditorGUI.BeginProperty(position, label, property);
            EditorGUI.LabelField(labelPosition, label);
            if (EditorGUI.DropdownButton(controlPosition, m_CurrentValueContent, FocusType.Keyboard))
            {
                CreateGenericMenu(property)
                    .DropDown(controlPosition);
            }
            EditorGUI.EndProperty();
        }
        
        private GenericMenu CreateGenericMenu(SerializedProperty property)
        {
            GameEnum gameEnum = (GameEnum)property.boxedValue;
            bool lockType = gameEnum.TypeLocked();
            GenerateGUITexts();
            GenericMenu menu = new GenericMenu();
            menu.AddItem(m_EmptyContent, string.IsNullOrEmpty(gameEnum.EnumTypeName()),
                () =>
                {
                    if (lockType)
                    {
                        property.boxedValue = new GameEnum(gameEnum.EnumTypeName(), string.Empty, lockType);
                    }
                    else
                    {
                        property.boxedValue = new GameEnum(string.Empty, string.Empty, lockType);
                    }
                    m_CurrentValueContent.text = m_EmptyContent.text;
                    property.serializedObject.ApplyModifiedProperties();
                });
            
            for (int i = 0; i < m_EnumTypeNames.Count; i++)
            {
                string typeName =  m_EnumTypeNames[i];
                string[] array =  m_EnumGUIArrays[typeName];
                for (int j = 0; j < array.Length; j++)
                {
                    string enumName = array[j];
                    bool isOn = typeName == gameEnum.EnumTypeName() && enumName == gameEnum.EnumName();
                    string text = string.Empty;
                    if (lockType)
                    {
                        text = enumName;
                    }
                    else
                    {
                        text = $"{typeName}/{enumName}";
                    }
                    
                    menu.AddItem(new GUIContent(text),isOn, () =>
                    {
                        var ge = new GameEnum(typeName, enumName, lockType);
                        property.boxedValue = ge;
                        m_CurrentValueContent.text = ge.ToString();
                        property.serializedObject.ApplyModifiedProperties();
                    });
                }
            }
            return menu;
        }
        
        private void GenerateGUITexts()
        {
            var enumMatrixConfig = EnumMatrixConfig.InstanceObject;
            m_EnumTypeNames.Clear();
            m_EnumGUIArrays.Clear();
            if (enumMatrixConfig != null && enumMatrixConfig.Containers.Count > 0)
            {
                m_EnumTypeNames.AddRange(enumMatrixConfig.Containers.Select(c=>c.name));
                for (int i = 0; i < enumMatrixConfig.Containers.Count; i++)
                {
                    var container = enumMatrixConfig.Containers[i];
                    string[] arr = container.contents.Select(e => e.name).ToArray();
                    m_EnumGUIArrays.Add(container.name, arr);
                }
            }
        }
    }
}